package entidades;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Classe para gerenciar uma Agenda de repeti��es de eventos.
 * 
 * @author Tales
 * 
 */
public class Agenda implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -994018536155995075L;
	private List<Data> datas;
	private Data inicio;
	private int repeticoes;
	private Map<Integer, Integer> mapaMesDias;
	
	private final int JAN = 1, FEV = 2, MAR = 3, ABR = 4, MAI = 5, JUN = 6, JUL = 7, AGO = 8, SET = 9, OUT = 10, NOV = 11, DEZ = 12;
	private final int fevereiroCom28Dias = 28, fevereiroCom29Dias = 29, mesCom30Dias = 30, mesCom31Dias = 31;
	private final int UMA_SEMANA = 7, NUM_MESES_DO_ANO = 12;
	
	/**
	 * Construtor de Agenda
	 * 
	 * @param inicio
	 *            - data de inicio do evento
	 * @param repeticoes
	 *            - numero de repeti��es que o evento ocorre a cada 7 dias.
	 */
	public Agenda(Data inicio, int repeticoes) {

		setRepeticoes(repeticoes);
		setInicio(inicio);
		datas = new ArrayList<Data>();
		montaMapa();
		geraReservas();

	}

	/**
	 * Construtor pronto para o Endode e Decode
	 */
	public Agenda() {

	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public Data getInicio() {
		return inicio;
	}

	public void setInicio(Data inicio) {
		this.inicio = inicio;
	}

	public int getRepeticoes() {
		return repeticoes;
	}

	public void setRepeticoes(int repeticoes) {
		this.repeticoes = repeticoes;
	}

	public Map<Integer, Integer> getMapaMesDias() {
		return mapaMesDias;
	}

	public void setMapaMesDias(Map<Integer, Integer> mapaMesDias) {
		this.mapaMesDias = mapaMesDias;
	}

	public void setDatas(List<Data> datas) {
		this.datas = datas;
	}

	private void montaMapa() {
		mapaMesDias = new HashMap<Integer, Integer>();
		mapaMesDias.put(JAN, mesCom31Dias);
		if (ehBissexto()) {
			mapaMesDias.put(FEV, fevereiroCom29Dias);
		} else {
			mapaMesDias.put(FEV, fevereiroCom28Dias);
		}
		mapaMesDias.put(MAR, mesCom31Dias);
		mapaMesDias.put(ABR, mesCom30Dias);
		mapaMesDias.put(MAI, mesCom31Dias);
		mapaMesDias.put(JUN, mesCom30Dias);
		mapaMesDias.put(JUL, mesCom31Dias);
		mapaMesDias.put(AGO, mesCom31Dias);
		mapaMesDias.put(SET, mesCom30Dias);
		mapaMesDias.put(OUT, mesCom31Dias);
		mapaMesDias.put(NOV, mesCom30Dias);
		mapaMesDias.put(DEZ, mesCom31Dias);

	}

	private boolean ehBissexto() {
		return (getInicio().getAno() - 2008) % 4 == 0;
	}

	private void geraReservas() {
		datas.add(new Data(getInicio().getDia(), getInicio().getMes(), getInicio().getAno()));
		int d = getInicio().getDia();
		int m = getInicio().getMes();
		int a = getInicio().getAno();

		for (int i = 0; i < repeticoes; i++) {
			if ( mesOverFlow(d, mapaMesDias.get(m)) ) {
				d = d + UMA_SEMANA - mapaMesDias.get(m);
				m = m + 1;
			} else {
				d = d + UMA_SEMANA;
			}
			if (anoOverFlow(m)) {
				m = 1;
				a = a + 1;
			}
			datas.add(new Data(d, m, a));
		}
	}

	/**
	 * Metodo para retornar uma lista de objetos da classe Data
	 * 
	 * @return - uma lista de objetos da classe Data
	 */
	public List<Data> getDatas() {
		return this.datas;
	}
	
	private boolean mesOverFlow(int dia, int numDeDiasDoMes){
		if(dia + UMA_SEMANA > numDeDiasDoMes){
			return true;
		}
		return false;
	}
	
	private boolean anoOverFlow(int mes){
		return (mes > NUM_MESES_DO_ANO);
	}

}
